#include "user.hpp"
#include "../my_server.hpp"
#include "user_client_ctx.hpp"
#include "../logger.hpp"
#include "../utils/random.hpp"
#include "../bubble/bubble.hpp"
#include "../room.hpp"

using namespace eiennet;
using namespace std;
using namespace winux;

uint User::UidCounter = 0;

User::User(UserClientCtx *clientCtx)
    : uid(++UidCounter),
      clientCtx(clientCtx)
{
}

void User::init(MyServer *server)
{
    this->server = server;
    Message msg(Message::MessageType::MCWelcome);
    emit(&msg);
}

User::~User()
{
}

winux::Mixed User::getInfo()
{
    winux::Mixed info;
    info.createCollection();
    info["uid"] = uid;
    info["name"] = name;
    info["head_id"] = headId;
    return info;
}

void User::emit(Message *msg)
{
    std::string str = LocalToUtf8(msg->data.json());
    TRACE("User::emit(Message *msg) msg:{0}", str);
    clientCtx->websocket.send(str);
}

void User::getRandomHead()
{
    headId = Random::range(1, 28);
}

void User::destroy()
{
    if (room)
    {
        this->exitRoom();
    }
}

void User::onMessage(std::string const &data)
{
    TRACE("[func] User::onMessage(std::string const& data ) data:{0}", data);
    try
    {
        Message msg(data);
        switch (msg.type)
        {
        case Message::MessageType::Unkonw:
            throw "message type unknow";
            break;
        case Message::MessageType::CMLoginGuest: //输入名字，登入
        {
            if (isLogged)
            {
                throw "不能重复登陆";
            }
            name = static_cast<std::string>(msg.data["name"]);
            isLogged = 1u;

            getRandomHead();

            Message resMsg(Message::MessageType::MCLoginGuest);
            resMsg.data["user_info"] = getInfo();
            emit(&resMsg);
        }
        break;
        case Message::MessageType::CMLogout:
        {
            if (!isLogged)
            {
                throw "你还没登陆";
            }
            if (room)
            {
                this->exitRoom();
            }
            name = "";
            isLogged = 0u;

            Message resMsg(Message::MessageType::MCLogout);
            emit(&resMsg);
        }
        break;
        case Message::MessageType::CMUserIn: //请求进入房间
        {
            if (room)
            {
                throw "你已经进入了房间";
            }
            this->enterRoom();

            //发送房间信息
            Message resMsg(Message::MessageType::MCRoomInfo);
            resMsg.data["room_info"] = this->room->getInfo();
            emit(&resMsg);
        }
        break;
        case Message::MessageType::CMUserOut: //请求退出房间。
        {
            if (!room)
            {
                throw "你没有进入房间";
            }
            this->exitRoom();
        }
        break;
        case Message::MessageType::CMAddBubble: //发言
        {
            if (!room)
            {
                throw "你没有进入房间";
            }
            //生成发言
            auto bubble = new Bubble(msg.data["text"], uid);
            this->room->bubbleList.push_back(std::shared_ptr<Bubble>(bubble));

            winux::Mixed info = bubble->getInfo();
            //响应请求
            Message resMsg(Message::MessageType::MCAddBubble);
            resMsg.data["bubble_info"] = info;
            emit(&resMsg);
            //广播发言
            Message bcMsg(Message::MessageType::MCArriveBubble);
            bcMsg.data["bubble_info"] = info;
            room->broadcast(&bcMsg, uid);
        }
        break;
        }
    }
    catch (char const *errStr)
    {
        Message msg(Message::MessageType::MCError);
        msg.data["desc"] = errStr;
        emit(&msg);
    }
    catch (...)
    {
        Message msg(Message::MessageType::MCError);
        msg.data["desc"] = "unknow error";
        emit(&msg);
    }
}

void User::enterRoom()
{
    server->userEnterRoom(this);

    //广播进入房间（响应进入房间）
    Message bcMsg(Message::MessageType::MCUserIn);
    bcMsg.data["user_info"] = getInfo();
    room->broadcast(&bcMsg);

    //发送公告消息
    std::string text = name;
    text += " 进入了房间";
    //生成服务器发言
    auto bubble = new Bubble(text, -1);
    this->room->bubbleList.push_back(std::shared_ptr<Bubble>(bubble));
    //广播服务器发言
    Message bcMsg2(Message::MessageType::MCArriveBubble);
    bcMsg2.data["bubble_info"] = bubble->getInfo();
    room->broadcast(&bcMsg2, uid);
}
void User::exitRoom()
{
    //广播退出房间（响应退出房间）
    Message bcMsg(Message::MessageType::MCUserOut);
    bcMsg.data["user_info"] = getInfo();
    room->broadcast(&bcMsg);

    //发送公告消息
    std::string text = name;
    text += " 离开了房间";
    //生成服务器发言
    auto bubble = new Bubble(text, -1);
    this->room->bubbleList.push_back(std::shared_ptr<Bubble>(bubble));
    //广播服务器发言
    Message bcMsg2(Message::MessageType::MCArriveBubble);
    bcMsg2.data["bubble_info"] = bubble->getInfo();
    room->broadcast(&bcMsg2, uid);

    room->delUser(uid);
    room = nullptr;
}